﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using CppIDE.Core;
using Application = CppIDE.Core.Application;

namespace CppIDE.UI
{

    /// <summary>
    /// A főablak osztálya.
    /// </summary>
    public partial class MainForm : Form
    {

        /// <summary>
        /// A MainForm konstruktora, privát, mert a statikus getInstance()
        /// segítségével kell a példányhoz hozzáférni.
        /// </summary>
        private MainForm()
        {
            InitializeComponent();
            projectTree.update();
            Application.getInstance().ActiveProjectChange += new EventHandler(MainForm_ActiveProjectChange);
            MainForm_ActiveProjectChange(this, null);
        }

        /// <summary>
        /// Az aktuális példány.
        /// </summary>
        private static MainForm instance = null;

        /// <summary>
        /// Visszaadja az aktuális példányt; ha nem létezik, akkor létrehozza.
        /// </summary>
        /// <returns>Az aktuális példány</returns>
        public static MainForm getInstance()
        {
            if (instance == null)
            {
                instance = new MainForm();
            }
            return instance;
        }

        /// <summary>
        /// Ha rákatinttottak a kilépésre, lépjünk ki.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void exitMenuItem_Click(object sender, EventArgs e)
        {
            Close();
        }

        /// <summary>
        /// Ez hívódik meg ha az aktuális projekt megváltozik.
        /// Frissítjük a gombok és menük állapotát. (Pl. ne lehessen proejektet
        /// menteni, ha nincs is megnyitott projekt.)
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MainForm_ActiveProjectChange(object sender, EventArgs e)
        {
            compileMenu.Enabled =
            compileButton.Enabled =
            projectPropertiesMenuItem.Enabled =
            projectPropertiesButton.Enabled =
            saveProjectMenuItem.Enabled =
            saveProjectButton.Enabled =
            closeProjectMenuItem.Enabled =
            closeProjectButton.Enabled =
                Application.getInstance().isProjectLoaded();
            tabControl_Change(sender, e); // to update the addFileMenuItem
        }

        /// <summary>
        /// Új projekt létrehozása (a gomb és menü eseménykezelője)
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void newProjectMenuItem_Click(object sender, EventArgs e)
        {
            if (!askAndSaveIfRequired()) return;
            Application.getInstance().newProject();
            new ProjectPropertiesForm().ShowDialog(this);
        }

        /// <summary>
        /// Ha van megnyitott projekt és az nem mentett, akkor rákérdez,
        /// hogy menteni szeretnénk-e és ha igen, akkor menti.
        /// </summary>
        /// <returns>ha igaz, már nincs mentendő projekt</returns>
        private bool askAndSaveIfRequired()
        {
            Application application = Application.getInstance();
            if (application.isProjectLoaded())
            {
                if (!application.ActiveProject.Saved)
                {
                    DialogResult result = MessageBox.Show("Szeretné menteni a jelenleg megnyitott projektet?", "Projekt mentése", MessageBoxButtons.YesNoCancel);
                    if (result == DialogResult.Cancel) return false;
                    if (result == DialogResult.Yes)
                    {
                        return saveProject();
                    }
                }
            }
            return true;
        }

        /// <summary>
        /// Projekt bezárása (a gomb és menü eseménykezelője)
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void closeProjectMenuItem_Click(object sender, EventArgs e)
        {
            DialogResult result = MessageBox.Show("Szeretni menteni a projektet bezárás előtt?", "Projekt mentése", MessageBoxButtons.YesNoCancel);
            if (result == DialogResult.Cancel) return;
            Application application = Application.getInstance();
            if (result == DialogResult.Yes)
            {
                if (!saveProject()) return;
            }
            application.closeProject();
        }

        /// <summary>
        /// Projekt tulajdonságai (a gomb és menü eseménykezelője)
        /// </summary>
        private void projectPropertiesMenuItem_Click(object sender, EventArgs e)
        {
            new ProjectPropertiesForm().ShowDialog(this);
        }

        /// <summary>
        /// Új fájl létrehozása (a gomb és menü eseménykezelője)
        /// </summary>
        private void newFileMenuItem_Click(object sender, EventArgs e)
        {
            FileTabPage tab = new FileTabPage();
            tabControl.add(tab);
            tabControl.SelectedTab = tab;
            tab.Focus();
        }

        /// <summary>
        /// Fájl megnyitása (a gomb és menü eseménykezelője)
        /// </summary>
        private void openMenuItem_Click(object sender, EventArgs e)
        {
            OpenFileDialog dialog = new OpenFileDialog();
            dialog.Filter =
                "Minden ismert |*.cpp;*.cxx;*.cc;*.h;*.hpp;*.hxx;*.c;*.xml|" +
                "C++ forrásfájl (*.cpp;*.cxx;*.cc)|*.cpp;*.cxx;*.cc|" +
                "Header fájl (*.h;*.hpp;*.hxx)|*.h;*.hpp;*.hxx|" +
                "C forrásfájl (*.c)|*.c|" +
                "C++ projektfájl (*.xml)|*.xml";
            Application application = Application.getInstance();
            if (application.isProjectLoaded())
            {
                Project project = application.ActiveProject;
                dialog.InitialDirectory = project.DirPath;
            }
            if (dialog.ShowDialog() != DialogResult.OK)
            {
                return;
            }
            if (dialog.FileName.EndsWith(".xml"))
            {
                application.openProject(dialog.FileName);
            }
            else
            {
                SourceFile file = SourceFile.factory(dialog.FileName);
                tabControl.activate(file);
            }
        }

        /// <summary>
        /// Fájl hozzáadása a projekthez (a gomb és menü eseménykezelője)
        /// </summary>
        private void addFileMenuItem_Click(object sender, EventArgs e)
        {
            if (tabControl.SelectedTab == null) return;
            if (!tabControl.SelectedTab.Saved)
            {
                DialogResult result = MessageBox.Show("Szeretné menteni a fájlt hozzáadás előtt?", "Fájl mentése", MessageBoxButtons.YesNoCancel);
                if (result == DialogResult.Cancel) return;
                if (result == DialogResult.Yes)
                {
                    if (!tabControl.SelectedTab.save())
                    {
                        return;
                    }
                }
            }
            Application.getInstance().ActiveProject.addFile(
                tabControl.SelectedTab.File
            );
        }

        /// <summary>
        /// Projekt mentése (a gomb és menü eseménykezelője)
        /// </summary>
        private void saveProjectMenuItem_Click(object sender, EventArgs e)
        {
            saveProject();
        }

        /// <summary>
        /// Projekt mentése: ha nincs hozzá társított fájl, akkor
        /// megkérdezi, hogy hova mentse.
        /// </summary>
        /// <returns>ha igaz, akkor a fájl mentése sikerült</returns>
        private bool saveProject()
        {
            Project project = Application.getInstance().ActiveProject;
            if (project.ProjectFile == null)
            {
                SaveFileDialog dialog = new SaveFileDialog();
                dialog.Filter = "C++ projektfájl (*.xml)|*.xml";
                dialog.InitialDirectory = project.DirPath;
                if (dialog.ShowDialog() != DialogResult.OK)
                {
                    return false;
                }
                project.ProjectFile = new File(dialog.FileName);
            }
            project.save();
            return true;
        }

        /// <summary>
        /// Projekt betöltése (a gomb és menü eseménykezelője)
        /// </summary>
        private void loadProjectMenuItem_Click(object sender, EventArgs e)
        {
            OpenFileDialog dialog = new OpenFileDialog();
            Application application = Application.getInstance();
            if (application.isProjectLoaded())
            {
                Project project = application.ActiveProject;
                dialog.InitialDirectory = project.DirPath;
            }
            if (!askAndSaveIfRequired()) return;
            dialog.Filter = "C++ projektfájl (*.xml)|*.xml";
            if (dialog.ShowDialog() != DialogResult.OK)
            {
                return;
            }
            application.openProject(dialog.FileName);
        }

        /// <summary>
        /// Megnyitja az aktuális fájlt és aktíválja a hozzá tartozó
        /// fület. Ha már meg van nyitva, akkor csak az utóbbi.
        /// </summary>
        public FileTabPage open(SourceFile file)
        {
            return tabControl.activate(file);
        }

        /// <summary>
        /// Fordítás (a gomb és menü eseménykezelője)
        /// </summary>
        private void compileMenuItem_Click(object sender, EventArgs e)
        {
            compile();
        }

        /// <summary>
        /// Fordítás.
        /// Ha van mentetlen fájl, akkor nem enged fordítani.
        /// Ha nincs beállítva a projekt kimenete, akkor rákérdez.
        /// </summary>
        /// <returns>a fordítás sikeressége</returns>
        private bool compile()
        {
            if (!saveAll())
            {
                MessageBox.Show("A fordításhoz minden megnyitott fájlt menteni kell!", "Hiba");
                return false;
            }
            buildLog.clear();
            buildLog.addLine("Fordítás folyamatban...");
            Application application = Application.getInstance();
            Project project = application.ActiveProject;
            if (project.Output == null)
            {
                MessageBox.Show("Még nincs beállítva a projekt kimenete, kérem tegye meg!", "Futtatható kimenet");
                SaveFileDialog dialog = new SaveFileDialog();
                dialog.Filter = "Futtatható fájl (*.exe)|*.exe";
                dialog.InitialDirectory = project.DirPath;
                if (dialog.ShowDialog() != DialogResult.OK)
                {
                    return false;
                }
                project.Output = new ExecutableFile(dialog.FileName);
            }
            bool success = false;
            buildLog.clear();
            try
            {
                List<Error> errors = application.ActiveProject.build(out success);
                foreach (Error error in errors)
                {
                    buildLog.addError(error);
                }
                if (success)
                {
                    buildLog.addLine("A fordítás sikerült!");
                }
                else
                {
                    buildLog.addLine("Sikertelen fordítás.");
                }
            }
            catch (Exception)
            {
                MessageBox.Show("A fordítás során probléma lépett fel.\nLehetséges, hogy nincs GCC feltelepítve vagy nem megfelelő a beálított útvonal?", "Hiba a fordítás közben", MessageBoxButtons.OK);
            }
            return success;
        }

        /// <summary>
        /// Tisztítás (a gomb és menü eseménykezelője)
        /// </summary>
        private void cleanMenuItem_Click(object sender, EventArgs e)
        {
            Application.getInstance().ActiveProject.clean();
        }

        /// <summary>
        /// Futtatás (a gomb és menü eseménykezelője)
        /// </summary>
        private void runMenuItem_Click(object sender, EventArgs e)
        {
            run();
        }

        /// <summary>
        /// Futtatás: az aktuális projekt kimenetének futtatása.
        /// </summary>
        private void run()
        {
            Application.getInstance().ActiveProject.execute();
        }

        /// <summary>
        /// Fordítás és futtatás (a gomb és menü eseménykezelője)
        /// </summary>
        private void compileRunMenuItem_Click(object sender, EventArgs e)
        {
            if (compile())
            {
                run();
            }
        }

        /// <summary>
        /// Minden újrafordítása (a gomb és menü eseménykezelője)
        /// </summary>
        private void rebuildAllMenuItem_Click(object sender, EventArgs e)
        {
            Project project = Application.getInstance().ActiveProject;
            project.clean();
            compile();
        }

        /// <summary>
        /// Összes mentése (a gomb és menü eseménykezelője)
        /// </summary>
        private void saveAllMenuItem_Click(object sender, EventArgs e)
        {
            saveAll();
        }

        /// <summary>
        /// Összes megnyitott fájl mentése.
        /// Ha van megnyitott projekt, azt is menti.
        /// </summary>
        public bool saveAll()
        {
            Application application = Application.getInstance();
            if (application.isProjectLoaded())
            {
                saveProject();
            }
            return tabControl.saveAll();
        }

        /// <summary>
        /// Bezáráskor hívódik meg: rákérdezünk, hogy szeretné menteni a mentetlen fájlokat ill.
        /// projektet.
        /// </summary>
        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (!askAndSaveIfRequired())
            {
                e.Cancel = true;
            }
            if (!tabControl.isAllSaved())
            {
                DialogResult result = MessageBox.Show("Szeretné menteni a módosított fájlokat?", "Fájlok mentése", MessageBoxButtons.YesNoCancel);
                if (result == DialogResult.Cancel) e.Cancel = true;
                if (result == DialogResult.Yes)
                {
                    saveAll();
                }
            }
            Application.getInstance().saveConfig();
        }

        /// <summary>
        /// Mentés (a gomb és menü eseménykezelője)
        /// </summary>
        private void saveMenuItem_Click(object sender, EventArgs e)
        {
            tabControl.SelectedTab.save();
        }

        /// <summary>
        /// Ha a megnyitt fájlok füleinél változás történik, ez hívódik meg.
        /// Frissítjük a gombokat és menüket (Pl.: ne lehessen menteni, ha
        /// az aktuális fájl már mentett).
        /// </summary>
        private void tabControl_Change(object sender, EventArgs e)
        {
            Application application = Application.getInstance();
            addFileMenuItem.Enabled =
            addFileButton.Enabled =
                application.isProjectLoaded() &&
                tabControl.SelectedTab != null &&
                !application.ActiveProject.contains(tabControl.SelectedTab.File);
            saveMenuItem.Enabled =
            saveButton.Enabled =
                tabControl.SelectedTab != null &&
                !tabControl.SelectedTab.Saved;
            closeFileMenuItem.Enabled =
            closeFileButton.Enabled =
                tabControl.SelectedTab != null;
        }

        /// <summary>
        /// Fájl bezárása (a gomb és menü eseménykezelője)
        /// </summary>
        private void closeFileMenuItem_Click(object sender, EventArgs e)
        {
            tabControl.CloseActive();
        }

        /// <summary>
        /// Beállítások (a gomb és menü eseménykezelője)
        /// </summary>
        private void configMenuItem_Click(object sender, EventArgs e)
        {
            new ConfigurationForm().ShowDialog();
        }

        /// <summary>
        /// Súgó (a menü eseménykezelője)
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void helpMenu_Click(object sender, EventArgs e)
        {
            new HelpForm().Show(this);
        }

    }

}
